#ifndef __CASE_HIERARCHICAL_STRUCTURE_H__
#define __CASE_HIERARCHICAL_STRUCTURE_H__

#include "basic/hs.h"
#include "basic/memory_pool.h"
#include "gtest/gtest.h"

using namespace basic;

class Test_hierarchical_structure : public testing::Test {
protected:
  HSForest* m_pForest{nullptr};
  bool b{false};
  void SetUp() override {
    m_pForest = new HSForest();
  };
  void TearDown() override {
    delete m_pForest;
  };
};

class NodeEx:public basic::HSNode{
  public:
    int GetTmp()const{return tmp;}
    void SetTmp(int v){tmp=v;}
  private:
  int tmp=10;
};

TEST_F(Test_hierarchical_structure, IsRootNode) {
  HSNode node, node2;

  ASSERT_EQ(m_pForest->IsRootNode(nullptr), false);
  ASSERT_EQ(m_pForest->IsRootNode(&node), true);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsRootNode(&node), true);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsRootNode(&node), true);
  ASSERT_EQ(m_pForest->IsRootNode(&node2), false);
}

TEST_F(Test_hierarchical_structure, IsLeafNode) {
  HSNode node;
  b = m_pForest->IsLeafNode(&node);
  ASSERT_EQ(b, true);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  b = m_pForest->IsLeafNode(&node);
  ASSERT_EQ(b, true);

  HSNode node2;
  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_FIRST_CHILD);
  b = m_pForest->IsLeafNode(&node);
  ASSERT_EQ(b, false);

  b = m_pForest->IsLeafNode(nullptr);
  ASSERT_EQ(b, false);
}

TEST_F(Test_hierarchical_structure, IsSibling) {
  HSNode node, node2;

  ASSERT_EQ(m_pForest->IsSibling(&node, &node2), false);
  ASSERT_EQ(m_pForest->IsSibling(&node, nullptr), false);
  ASSERT_EQ(m_pForest->IsSibling(nullptr, &node2), false);
  ASSERT_EQ(m_pForest->IsSibling(nullptr, nullptr), false);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsSibling(&node, &node2), false);
  ASSERT_EQ(m_pForest->IsSibling(&node, nullptr), false);
  ASSERT_EQ(m_pForest->IsSibling(nullptr, &node2), false);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsSibling(&node, &node2), true);
  ASSERT_EQ(m_pForest->IsSibling(&node, nullptr), false);
  ASSERT_EQ(m_pForest->IsSibling(nullptr, &node2), false);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsSibling(&node, &node2), false);
}

TEST_F(Test_hierarchical_structure, IsDirectDependent) {
  HSNode node, node2;

  ASSERT_EQ(m_pForest->IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node, nullptr), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(nullptr, &node2), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(nullptr, nullptr), false);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node, nullptr), false);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node, nullptr), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(nullptr, &node2), false);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(m_pForest->IsDirectDependent(&node2, &node), true);
}

TEST_F(Test_hierarchical_structure, GetFirstChild) {
  HSNode node, node2;

  ASSERT_EQ(m_pForest->GetFirstChild(&node), nullptr);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), nullptr);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), nullptr);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node2);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), &node2);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node);
  ASSERT_EQ(m_pForest->GetFirstChild(&node2), nullptr);
}

TEST_F(Test_hierarchical_structure, GetSibling) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetSibling(&node, -1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(&node, 0, false), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(&node, -1, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 0, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 1, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(nullptr, -1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(nullptr, 0, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(nullptr, 1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(nullptr, -1, true), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(nullptr, 0, true), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(nullptr, 1, true), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD);
  ASSERT_EQ(m_pForest->GetSibling(&node, -1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(&node, 0, false), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(&node, -1, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 0, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 1, true), &node);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetSibling(&node, 0, false), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 1, false), &node2);
  ASSERT_EQ(m_pForest->GetSibling(&node, -1, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(&node, -1, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 0, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node, 1, true), &node2);

  m_pForest->Insert(&node3, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetSibling(&node2, -1, false), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node2, 0, false), &node2);
  ASSERT_EQ(m_pForest->GetSibling(&node2, 1, false), &node3);
  ASSERT_EQ(m_pForest->GetSibling(&node2, 2, false), nullptr);
  ASSERT_EQ(m_pForest->GetSibling(&node2, -1, true), &node);
  ASSERT_EQ(m_pForest->GetSibling(&node2, 0, true), &node2);
  ASSERT_EQ(m_pForest->GetSibling(&node2, 1, true), &node3);
  ASSERT_EQ(m_pForest->GetSibling(&node2, 2, true), &node3);
}

TEST_F(Test_hierarchical_structure, GetNextSibling) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetNextSibling(&node), nullptr);
  ASSERT_EQ(m_pForest->GetNextSibling(nullptr), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetNextSibling(&node), nullptr);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetNextSibling(&node2), nullptr);
  ASSERT_EQ(m_pForest->GetNextSibling(&node), &node2);

  m_pForest->Insert(&node3, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetNextSibling(&node), &node2);
  ASSERT_EQ(m_pForest->GetNextSibling(&node2), &node3);
  ASSERT_EQ(m_pForest->GetNextSibling(&node3), nullptr);
}

TEST_F(Test_hierarchical_structure, GetPreSibling) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetPreSibling(&node), nullptr);
  ASSERT_EQ(m_pForest->GetPreSibling(nullptr), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetPreSibling(&node), nullptr);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetPreSibling(&node), nullptr);
  ASSERT_EQ(m_pForest->GetPreSibling(&node2), &node);

  m_pForest->Insert(&node3, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetPreSibling(&node), nullptr);
  ASSERT_EQ(m_pForest->GetPreSibling(&node2), &node);
  ASSERT_EQ(m_pForest->GetPreSibling(&node3), &node2);
}

TEST_F(Test_hierarchical_structure, GetParent) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetParent(&node), nullptr);
  ASSERT_EQ(m_pForest->GetParent(nullptr), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetParent(&node), nullptr);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetParent(&node), nullptr);
  ASSERT_EQ(m_pForest->GetParent(&node2), nullptr);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node3, &node2, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetParent(&node), nullptr);
  ASSERT_EQ(m_pForest->GetParent(&node2), &node);
  ASSERT_EQ(m_pForest->GetParent(&node3), &node2);
}

TEST_F(Test_hierarchical_structure, GetRoot) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetRoot(&node), &node);
  ASSERT_EQ(m_pForest->GetRoot(nullptr), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetRoot(&node), &node);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetRoot(&node), &node);
  ASSERT_EQ(m_pForest->GetRoot(&node2), &node2);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node3, &node2, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetRoot(&node), &node);
  ASSERT_EQ(m_pForest->GetRoot(&node2), &node);
  ASSERT_EQ(m_pForest->GetRoot(&node3), &node);
}

TEST_F(Test_hierarchical_structure, GetOffset) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetOffset(&node), M_INVALID_OFFSET);
  ASSERT_EQ(m_pForest->GetOffset(nullptr), M_INVALID_OFFSET);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetOffset(&node), M_INVALID_OFFSET);

  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetOffset(&node), M_INVALID_OFFSET);
  ASSERT_EQ(m_pForest->GetOffset(&node2), M_INVALID_OFFSET);

  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node3, &node, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetOffset(&node), M_INVALID_OFFSET);
  ASSERT_EQ(m_pForest->GetOffset(&node2), 0);
  ASSERT_EQ(m_pForest->GetOffset(&node3), 1);
}

TEST_F(Test_hierarchical_structure, Remove) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->Remove(&node), HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(m_pForest->Remove(nullptr), HSNodeResult::RESULT_INVALID_VALUE);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node);
  ASSERT_EQ(m_pForest->Remove(&node), HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node);
  ASSERT_EQ(m_pForest->Remove(&node), HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node2);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node3, &node, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), &node2);
  ASSERT_EQ(m_pForest->Remove(&node2), HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), &node3);
  ASSERT_EQ(m_pForest->GetFirstChild(&node2), nullptr);

  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD);
  m_pForest->Insert(&node3, &node2, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetFirstChild(nullptr), &node);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), &node2);
  ASSERT_EQ(m_pForest->GetFirstChild(&node2), &node3);
  ASSERT_EQ(m_pForest->Remove(&node2), HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(m_pForest->GetFirstChild(&node), nullptr);
  ASSERT_EQ(m_pForest->GetFirstChild(&node2), &node3);
}

TEST_F(Test_hierarchical_structure, Insert) {
  HSNode node, node2, node3;

  ASSERT_EQ(
      m_pForest->Insert(nullptr, nullptr, HSNodeRelation::RELATION_FIRST_CHILD),
      HSNodeResult::RESULT_INVALID_VALUE);
  ASSERT_EQ(
      m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_FIRST_CHILD),
      HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(
      m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_NEXT_SIBLING),
      HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(
      m_pForest->Insert(&node3, nullptr, HSNodeRelation::RELATION_LAST_CHILD),
      HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(
      m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD),
      HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(
      m_pForest->Insert(&node3, &node2, HSNodeRelation::RELATION_LAST_CHILD),
      HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(
      m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_FIRST_CHILD),
      HSNodeResult::RESULT_SUCCESS);
  ASSERT_EQ(
      m_pForest->Insert(nullptr, nullptr, HSNodeRelation::RELATION_FIRST_CHILD),
      HSNodeResult::RESULT_INVALID_VALUE);
}

TEST_F(Test_hierarchical_structure, GetChildrenCount) {
  HSNode node, node2, node3;

  ASSERT_EQ(m_pForest->GetChildrenCount(nullptr), 0);
  m_pForest->Insert(&node, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetChildrenCount(nullptr), 1);
  m_pForest->Insert(&node2, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetChildrenCount(nullptr), 2);
  m_pForest->Insert(&node3, nullptr, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetChildrenCount(nullptr), 3);
  m_pForest->Insert(&node2, &node, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetChildrenCount(nullptr), 2);
  ASSERT_EQ(m_pForest->GetChildrenCount(&node), 1);
  ASSERT_EQ(m_pForest->GetChildrenCount(&node2), 0);
  m_pForest->Insert(&node3, &node2, HSNodeRelation::RELATION_LAST_CHILD);
  ASSERT_EQ(m_pForest->GetChildrenCount(nullptr), 1);
  ASSERT_EQ(m_pForest->GetChildrenCount(&node), 1);
  ASSERT_EQ(m_pForest->GetChildrenCount(&node2), 1);
  ASSERT_EQ(m_pForest->GetChildrenCount(&node3), 0);
}

TEST(Test_HSProcessor, IsDirectDependent) {
  HSNode node, node2;

  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, nullptr), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(nullptr, &node2), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(nullptr, nullptr), false);

  HSProcessor::InsertAsFirstChild(&node, nullptr);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, nullptr), false);

  HSProcessor::InsertAsFirstChild(&node2, nullptr);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, nullptr), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(nullptr, &node2), false);

  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node, &node2), false);
  ASSERT_EQ(HSProcessor::IsDirectDependent(&node2, &node), true);
}

TEST(Test_HSProcessor, GetFirstChild) {
  NodeEx node10,node20,node30;
  ASSERT_EQ(node10.GetFirstChild<NodeEx*>(), nullptr);

  HSProcessor::InsertAsFirstChild(&node20, &node10);
  ASSERT_EQ(node10.GetFirstChild<NodeEx*>(), &node20);
  ASSERT_EQ(node10.GetFirstChild(), &node20);
  ASSERT_EQ(node10.GetFirstChild<NodeEx*>()->GetTmp(), 10);
  node10.GetFirstChild<NodeEx*>()->SetTmp(20);
  ASSERT_EQ(node10.GetFirstChild<NodeEx*>()->GetTmp(), 20);

  HSProcessor::InsertAsFirstChild(&node30, &node10);
  ASSERT_EQ(node10.GetFirstChild<NodeEx*>(), &node30);

  HSProcessor::InsertAsLastChild(&node30, &node10);
  ASSERT_EQ(node10.GetFirstChild<NodeEx*>(), &node20);
}

TEST(Test_HSProcessor, GetSiblingAt) {
  HSNode node, node2, node3, node4;

  ASSERT_EQ(HSProcessor::GetSiblingAt(nullptr, -1), nullptr);
  ASSERT_EQ(HSProcessor::GetSiblingAt(nullptr, 0), nullptr);
  ASSERT_EQ(HSProcessor::GetSiblingAt(nullptr, 1), nullptr);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, -1), nullptr);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 0), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 1), nullptr);

  HSProcessor::InsertAsNextSibling(&node2, &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, -1), nullptr);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 0), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 1), &node2);

  HSProcessor::InsertAsNextSibling(&node3, &node2);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, -1), nullptr);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 0), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 1), &node2);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 2), &node3);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, -1), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, 0), &node2);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, 1), &node3);

  HSProcessor::InsertAsPreSibling(&node4, &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, -1), &node4);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 0), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 1), &node2);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node, 2), &node3);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, -2), &node4);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, -1), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, 0), &node2);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node2, 1), &node3);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node3, -3), &node4);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node3, -2), &node);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node3, -1), &node2);
  ASSERT_EQ(HSProcessor::GetSiblingAt(&node3, 0), &node3);
}

TEST(Test_HSProcessor, GetNextSibling) {
  NodeEx node, node2, node3, node4;

  // ASSERT_EQ(HSProcessor::GetNextSibling(nullptr),nullptr);
  ASSERT_EQ(node.GetNextSibling(), nullptr);

  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(node.GetNextSibling(), nullptr);
  ASSERT_EQ(node.GetNextSibling<NodeEx*>(), nullptr);
  ASSERT_EQ(node2.GetNextSibling(), nullptr);
  ASSERT_EQ(node2.GetNextSibling<NodeEx*>(), nullptr);

  HSProcessor::InsertAsLastChild(&node3, &node);
  ASSERT_EQ(node2.GetNextSibling(), &node3);
  ASSERT_EQ(node2.GetNextSibling<NodeEx*>(), &node3);
  ASSERT_EQ(node3.GetNextSibling(), nullptr);
  ASSERT_EQ(node3.GetNextSibling<NodeEx*>(), nullptr);

  HSProcessor::InsertAsLastChild(&node4, &node);
  ASSERT_EQ(node2.GetNextSibling(), &node3);
  ASSERT_EQ(node2.GetNextSibling<NodeEx*>(), &node3);
  ASSERT_EQ(node3.GetNextSibling(), &node4);
  ASSERT_EQ(node3.GetNextSibling<NodeEx*>(), &node4);
  ASSERT_EQ(node4.GetNextSibling(), nullptr);
  ASSERT_EQ(node4.GetNextSibling<NodeEx*>(), nullptr);
}

TEST(Test_HSProcessor, GetPreSibling) {
  HSNode node, node2, node3, node4;

  // ASSERT_EQ(HSProcessor::GetPreSibling(nullptr),nullptr);
  ASSERT_EQ(node.GetPreSibling(), nullptr);
  ASSERT_EQ(node.GetPreSibling<NodeEx*>(), nullptr);

  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(node.GetPreSibling(), nullptr);
  ASSERT_EQ(node.GetPreSibling<NodeEx*>(), nullptr);
  ASSERT_EQ(node2.GetPreSibling(), nullptr);
  ASSERT_EQ(node2.GetPreSibling<NodeEx*>(), nullptr);

  HSProcessor::InsertAsLastChild(&node3, &node);
  ASSERT_EQ(node2.GetPreSibling(), nullptr);
  ASSERT_EQ(node2.GetPreSibling<NodeEx*>(), nullptr);
  ASSERT_EQ(node3.GetPreSibling(), &node2);
  ASSERT_EQ(node3.GetPreSibling<NodeEx*>(), nullptr);

  HSProcessor::InsertAsLastChild(&node4, &node);
  ASSERT_EQ(node2.GetPreSibling(), nullptr);
  ASSERT_EQ(node2.GetPreSibling<NodeEx*>(), nullptr);
  ASSERT_EQ(node3.GetPreSibling(), &node2);
  ASSERT_EQ(node3.GetPreSibling<NodeEx*>(), nullptr);
  ASSERT_EQ(node4.GetPreSibling(), &node3);
  ASSERT_EQ(node4.GetPreSibling<NodeEx*>(), nullptr);
}

TEST(Test_HSProcessor, GetParent) {
  NodeEx node, node2;
  HSNode node3, node4;

  // ASSERT_EQ(HSProcessor::GetParent(nullptr),nullptr);
  ASSERT_EQ(node.GetParent(), nullptr);
  ASSERT_EQ(node.GetParent<HSNode*>(), nullptr);

  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(node.GetParent(), nullptr);
  ASSERT_EQ(node.GetParent<NodeEx*>(), nullptr);
  ASSERT_EQ(node2.GetParent(), &node);
  ASSERT_EQ(node2.GetParent<NodeEx*>(), &node);

  HSProcessor::InsertAsFirstChild(&node3, &node);
  ASSERT_EQ(node.GetParent(), nullptr);
  ASSERT_EQ(node.GetParent<NodeEx*>(), nullptr);
  ASSERT_EQ(node2.GetParent(), &node);
  ASSERT_EQ(node2.GetParent<NodeEx*>(), &node);
  ASSERT_EQ(node3.GetParent(), &node);
  ASSERT_EQ(node3.GetParent<NodeEx*>(), &node);

  HSProcessor::InsertAsFirstChild(&node4, &node);
  ASSERT_EQ(node.GetParent(), nullptr);
  ASSERT_EQ(node.GetParent<NodeEx*>(), nullptr);
  ASSERT_EQ(node2.GetParent(), &node);
  ASSERT_EQ(node2.GetParent<NodeEx*>(), &node);
  ASSERT_EQ(node3.GetParent(), &node);
  ASSERT_EQ(node3.GetParent<NodeEx*>(), &node);
  ASSERT_EQ(node4.GetParent(), &node);
  ASSERT_EQ(node4.GetParent<NodeEx*>(), &node);
}

TEST(Test_HSProcessor, GetRoot) {
  HSNode node, node2, node3, node4;

  // ASSERT_EQ(HSProcessor::GetRoot(nullptr),nullptr);
  ASSERT_EQ(HSProcessor::GetRoot(&node), &node);

  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node), &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node2), &node);

  HSProcessor::InsertAsFirstChild(&node3, &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node), &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node2), &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node3), &node);

  HSProcessor::InsertAsFirstChild(&node4, &node2);
  ASSERT_EQ(HSProcessor::GetRoot(&node), &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node2), &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node3), &node);
  ASSERT_EQ(HSProcessor::GetRoot(&node4), &node);
}

TEST(Test_HSProcessor, Remove) {
  HSNode node, node2, node3, node4;

  HSProcessor::Remove(nullptr);
  HSProcessor::Remove(&node);

  ASSERT_EQ(node.GetFirstChild<HSNode*>(), nullptr);

  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(node.GetFirstChild(), &node2);
  HSProcessor::Remove(&node);
  ASSERT_EQ(node.GetFirstChild(), &node2);
  HSProcessor::Remove(&node2);
  ASSERT_EQ(node.GetFirstChild(), nullptr);

  HSProcessor::InsertAsFirstChild(&node3, &node);
  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(node.GetFirstChild(), &node2);
  HSProcessor::Remove(&node2);
  ASSERT_EQ(node.GetFirstChild(), &node3);

  HSProcessor::InsertAsFirstChild(&node4, &node);
  HSProcessor::InsertAsFirstChild(&node3, &node);
  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(node.GetFirstChild(), &node2);
  ASSERT_EQ(HSProcessor::GetLastChild(&node), &node4);
  HSProcessor::Remove(&node4);
  ASSERT_EQ(HSProcessor::GetLastChild(&node), &node3);

  HSProcessor::InsertAsFirstChild(&node3, &node);
  HSProcessor::InsertAsFirstChild(&node2, &node);
  HSProcessor::InsertAsFirstChild(&node4, &node2);
  ASSERT_EQ(node.GetFirstChild(), &node2);
  ASSERT_EQ(HSProcessor::GetLastChild(&node), &node3);
  ASSERT_EQ(node2.GetFirstChild(), &node4);
  ASSERT_EQ(HSProcessor::GetLastChild(&node2), &node4);
  HSProcessor::Remove(&node3);
  ASSERT_EQ(HSProcessor::GetLastChild(&node), &node2);
}

/*
TEST(Test_HSProcessor,InsertAsFirstChild){
    HSNode node,node2,node3;

    ASSERT_EQ(HSProcessor::InsertAsFirstChild(nullptr,nullptr);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(&node,nullptr);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(&node2,&node);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(&node3,nullptr);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(&node2,&node);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(&node3,&node2);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(&node2,nullptr);
    ASSERT_EQ(HSProcessor::InsertAsFirstChild(nullptr,nullptr);
}
*/

TEST(Test_HSProcessor, GetChildrenCount) {
  HSNode node, node2, node3, node4;

  ASSERT_EQ(HSProcessor::GetChildrenCount(nullptr), 0);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node), 0);
  HSProcessor::InsertAsFirstChild(&node2, &node);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node), 1);
  HSProcessor::InsertAsFirstChild(&node3, &node);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node), 2);
  HSProcessor::InsertAsFirstChild(&node4, &node);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node), 3);
  HSProcessor::InsertAsFirstChild(&node3, &node2);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node), 2);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node2), 1);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node3), 0);
  HSProcessor::InsertAsFirstChild(&node4, &node3);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node), 1);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node2), 1);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node3), 1);
  ASSERT_EQ(HSProcessor::GetChildrenCount(&node4), 0);
}

TEST(Test_HSProcessor, coat_1000000_time) {
  HSNode node;
  DKMemoryAllocator* pA = new DKMemoryAllocator();
  pA->SetMemoryBlock(new DKMemoryBlock(1 << 30)); // 1GiB

  const int M{1000000};
  HSNode* pNode = pA->Allocate<HSNode>(M);

  for (int i = 0; i < M; ++i) {
    HSProcessor::InsertAsFirstChild(&(pNode[i]), &node);
  }

  delete pA;
}

#endif
